﻿#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
/************************22.动态内存管理************************/
//创建变量的本质是向内存申请空间
//int main()
//{
//	int a = 10;
//	int arr[10];
//	//创建好后内存大小固定无法改变
//
//	return 0;
//}
//变量和数组的方式不够灵活
//使用动态内存分配可以自己维护内存的使用生命周期

/*1.动态内存管理的函数*/
//malloc函数
//free函数

//#include <stdlib.h>
//
//int main()
//{
//	//申请40个字节，存放10个整数
//	//int* p = (int*)malloc(40);
//
//	int* p = (int*)malloc(INT_MAX);
//	//开辟成功，返回⼀个指向开辟好空间的指针。
//	//开辟失败，返回⼀个 NULL 指针，因此malloc的返回值⼀定要做检查
//	if (p == NULL)
//	{
//		perror("malloc");//打印开辟失败原因
//		return 1;//失败返回
//		
//	}
//
//	//使用内存
//	int i = 0;
//	for (i = 0; i < 10; i++)
//	{
//		*(p + i) = i + 1;
//	}
//
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d ",*(p + i));
//	}
//
//	//释放空间
//	free(p);
//
//	//指针置空
//	p = NULL;
//
//	return 0;//正常返回
//	/*main函数的返回值*/
//	//main函数也是函数
//		//main函数也是被其他函数调用的
//		//通过main函数返回值了解main函数是否正常执行
//}

//calloc函数
//函数的功能是为 num 个⼤⼩为 size 的元素开辟⼀块空间，并且把空间的每个字节初始化为0。
//#include <stdlib.h>
//
//int main()
//{
//	int* p = (int*)calloc(10,sizeof(int));//全为0
//	//int* p = (int*)malloc(10, sizeof(int));//随机值
//
//	if (p == NULL)
//	{
//		perror("calloc");//打印开辟失败原因
//		return 1;//失败返回
//				
//	}
//	//使用
//	int i = 0;
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d ",*(p + i));
//	}
//	printf("\n%d", p[2] = 3);
//	//释放
//	free(p);
//	p = NULL;
//
//	return 0;
//}

//realloc函数
/*可以调整内存，申请内存*/
#include <stdlib.h>
//int main()
//{
//	//申请5个整型的空间
//	int* p = (int*)malloc(5 * sizeof(int));
//	if (p == NULL)
//	{
//		perror("malloc");
//		return 1;
//	}
//	//使用
//	int i = 0;
//	for (i = 0; i < 5; ++i)
//	{
//		*(p + i) = i + 1;
//	}
//	//空间不足，希望存放1~10
//	//申请更多的空间 - 调整空间
//	int* ptr = (int*)realloc(p, 10*sizeof(int));
//	if (ptr == NULL)
//	{
//		perror("realloc");
//		return 1;
//	}
//	else
//	{
//		p = ptr;
//	}
//	for (i = 5; i < 10; i++)
//	{
//		*(p + i) = i + 1;
//	}
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d ",*(p + i));
//	}
//	//释放
//	free(p);
//	p = NULL;
//	return 0;
//}

//开辟空间
//int main()
//{
//	int* p = (int*)realloc(NULL, 10 * sizeof(int));
//	return 0;
//}

/*2.常⻅的动态内存的错误*/
//对NULL指针的解引⽤操作
//int main()
//{
//	int* p = (int*)malloc(INT_MAX);
//	*p = 20;//如果p的值是NULL，就会有问题
//	printf("%d",*p);//打印不出20
//	free(p);
//	p = NULL;
//	return 0;
//}

//对动态开辟空间的越界访问
//int main()
//{
//	int* p = (int*)malloc(10 * sizeof(int));
//	if (p = NULL)
//		return 1;
//
//	int i = 0;
//	for (i = 0; i <= 10; i++)//i<=10越界访问了
//	{
//		*(p + i) = i + 1;
//	}
//
//	free(p);
//	p = NULL;
//	return 0;
//}

//对⾮动态开辟内存使⽤free释放
//int main()
//{
//	int arr[10] = { 0 };
//	int* p = arr;
//
//	free(p);//使用free释放非动态开辟内存
//	p = NULL;
//	return 0;
//}

//使⽤free释放⼀块动态开辟内存的⼀部分
//int main()
//{
//	int* p = (int*)malloc(10 * sizeof(int));
//	if (p = NULL)
//		return 1;
//
//	int i = 0;
//
//	for (i = 0; i < 5; i++)//i<=10越界访问了
//	{
//		*p = i + 1;
//		p++;//此时p被改变了
//	}
//
//	free(p);//释放5之后的动态开辟的内存，5之前的没有释放
//	//free函数的参数要释放空间的起始位置
//
//	p = NULL;
//	return 0;
//}

//对同⼀块动态内存多次释放
//int main()
//{
//	int* p = (int*)malloc(100);
//	free(p);
//	free(p);//重复释放
//	p = NULL;
//}

//动态开辟内存忘记释放（内存泄漏）
//int main()
//{
//	int* p = (int*)malloc(100);
//	free(p);
//
//	//野指针
//	//p = NULL;不置空
//
//}

//void test()
//{
//	int* p = (int*)malloc(100);
//	if (NULL != p)
//	{
//		*p = 20;
//	}
//}
//
//int main()
//{
//	test();
//	//出函数没释放，内存泄漏。
//	return 0;
//}

/*练习*/
/*void GetMemory(char* p)
{
	p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");//对空指针解引用，非法访问内存
	printf(str);
}*/ //修改这段代码
#include <string.h>
//方法一
//char* GetMemory()
//{
//	char* p = (char*)malloc(100);
//	return p;
//}
//void Test(void)
//{
//	char* str = NULL;
//	str = GetMemory();
//	strcpy(str, "hello world");
//	printf(str);
//}

//方法二
//void GetMemory(char** p)
//{
//	*p = (char*)malloc(100);
//}
//void Test(void)
//{
//	char* str = NULL;
//	GetMemory(&str);
//	strcpy(str, "hello world");
//	printf(str);
//}
//int main()
//{
//	Test();
//	return 0;
//}

/*运⾏Test 函数*/
//char* GetMemory(void)
//{
//	char p[] = "hello world";//出函数就回收内存空间
//	return p;
//}
//void Test(void)
//{
//	char* str = NULL;
//	str = GetMemory();//str变野指针
//	printf(str);
//}
//
//int main()
//{
//	Test();
//	return 0;
//}

//void GetMemory(char** p, int num)
//{
//	*p = (char*)malloc(num);
//}
//void Test(void)
//{
//	char* str = NULL;
//	GetMemory(&str, 100);
//	strcpy(str, "hello");
//	printf(str);//没有释放空间，内存泄漏
//	/*修改处*/
//	free(str);
//	str = NULL;
//}
//
//int main()
//{
//	Test();
//	return 0;
//}

//void Test(void)
//{
//	char* str = (char*)malloc(100);
//	strcpy(str, "hello");
//	free(str);//野指针，没有指针置空
//	/*修改处*/
//	str = NULL;
//	if (str != NULL)
//	{
//		strcpy(str, "world"); //非法访问
//		printf(str);
//	}
//}
//
//int main()
//{
//	Test();
//	return 0;
//}

/*4.柔性数组*/
//结构中的最后⼀个元素允许是未知⼤⼩的数组，这就叫做『柔性数组』成员
//struct S
//{
//	int i;
//	int a[0];//柔性数组成员，大小未知
//};

/*特点*/
/*结构中的柔性数组成员前⾯必须⾄少⼀个其他成员。
sizeof 返回的这种结构⼤⼩不包括柔性数组的内存。
包含柔性数组成员的结构⽤malloc()函数进⾏内存的动态分配，并且分配的内存应该⼤于结构的⼤
⼩，以适应柔性数组的预期⼤⼩。*/

//struct S
//{
//	int i;
//	int a[0];//柔性数组成员，大小未知
//};
//
//int main()
//{
//	printf("%zd ",sizeof(struct S));//4
//	return 0;
//}

//struct S
//{
//	int n;
//	int a[];//柔性数组成员，大小未知
//};
//
//int main()
//{
//	struct S* ps= (struct S*)malloc(sizeof(struct S) + 10 * sizeof(int));//4
//	if (ps == NULL)
//	{
//		perror("malloc");
//		return 1;
//	}
//	ps->n = 100;
//	int i = 0;
//	for (i = 0; i < 10; i++)
//	{
//		ps->a[i] = i + 1;
//	}
//	//如果空间不够，动态调整
//	struct S* ptr = (struct S*)realloc(ps,sizeof(struct S) + 20 * sizeof(int));
//	if (ptr == NULL)
//	{
//		perror("realloc");
//		return 1;
//	}
//	ps = ptr;
//
//	free(ps);
//	ps = NULL;
//
//	return 0;
//}

struct S2
{
	int n;
	int* a;
};

int main()
{
	struct S2* ps = (struct S2*)malloc(sizeof(struct S2));
	if (ps == NULL)
	{
		perror("malloc");
		return 1;
	}
	ps->n;
	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL)
	{
		perror("malloc2");
		return 1;
	}
	ps->a = p;
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		ps->a[i] = i + 1;
	}
	//如果空间不够，动态调整
	int* p2 = (int*)realloc(ps->a, 20 * sizeof(int));
	if (p2 == NULL)
	{
		perror("realloc");
		return 1;
	}
	ps->a = p2;

	free(ps->a);
	ps->a = NULL;
	free(ps);
	ps = NULL;;

	return 0;
}





